Strict

import mojo

' Store the device width and height
Global SCREEN_WIDTH%
Global SCREEN_HEIGHT%

' Game Width and Height
Const WIDTH#=320
Const HEIGHT#=240

' Used for delta timing movement
Global dt:DeltaTimer

Global game:MyGame

Function Main:int()
	game = new MyGame()
	return 0
End Function

Class MyGame extends App
	Field player:Player
	Field level:Level
	Field FPS% = 60
	Field offsetX#, offsetY#
	Field scrollX#, scrollY#
	
	Method OnCreate:Int()
		' Create the delta timer
		dt = New DeltaTimer(FPS)
		SetUpdateRate FPS
		
		' Store the device width and height
		SCREEN_WIDTH = DeviceWidth()
		SCREEN_HEIGHT = DeviceHeight()
		
		level = new Level()
		level.load()
		
		player = new Player(level.playerX, level.playerY)
		
		return 0
	End Method
	
	Method OnUpdate:Int()
		dt.UpdateDelta()
		player.update()
		return 0
	End Method
	
	Method OnRender:Int()
		Cls 
		PushMatrix 
		Scale SCREEN_WIDTH/WIDTH, SCREEN_HEIGHT/HEIGHT
		level.draw()
		player.draw(game.scrollX, game.scrollY)
		PopMatrix
		return 0
	End Method	
end class

Class GameImage
	Field w%, h%
	Field w2%, h2%
End Class

Class Player
	Field x#, y#
	Field dx#, dy#
	Field speedX#, speedY#
	Field image:GameImage
	Field jumping:Bool
	
	Method New(x#, y#)
		self.x = x
		self.y = y
		image = new GameImage
		image.w = 16
		image.h = 16
		image.w2 = image.w / 2
		image.h2 = image.h / 2
		speedX = 2
		speedY = 5
	End Method
	
	Method draw:Void(offsetx# = 0, offsety# = 0)
		SetColor 0,255,0
		DrawOval x - image.w2 - offsetx, y - image.h2 - offsety, image.w, image.h
		SetColor 255, 255, 255
	End Method
	
	Method update:Void()
	
		if KeyDown(KEY_LEFT)
			Local tempx# = x - speedX * dt.delta
			if game.level.getCollisionTile(tempx - image.w2 , y + image.h2 - 1 ) = 0 and
				game.level.getCollisionTile(tempx - image.w2 , y - image.h2) = 0 and
				game.level.getCollisionTile(tempx - image.w2 , y) = 0 then
						
				x = tempx
			else
				x = round((x-image.w2)/Level.TILE_SIZE)*Level.TILE_SIZE + image.w2
			endif
		else if KeyDown(KEY_RIGHT)
			Local tempx# = x + speedX * dt.delta
			if game.level.getCollisionTile(tempx + image.w2 , y + image.h2 - 1 ) = 0 and
				game.level.getCollisionTile(tempx + image.w2 , y - image.h2) = 0 and
				game.level.getCollisionTile(tempx + image.w2 , y) = 0 then
				
				x = tempx
			else
				x = round((x+image.w2)/Level.TILE_SIZE)*Level.TILE_SIZE - image.w2
			endif
		End if
		
		If KeyDown(KEY_SPACE) And not jumping Then
			dy=-speedY
			jumping = true
		EndIf
		
		Local amount:Int = 1
		Local amountY:int = 1
		
		if not jumping
			if game.level.getCollisionTile(x - image.w2 + amount, y + image.h2) = 0 and 
				game.level.getCollisionTile(x + image.w2 - amount, y + image.h2) = 0 and 
				game.level.getCollisionTile(x, y + image.h2) = 0 then
				
				jumping = true
			endif
		endif
		
		if jumping
			dy +=Level.GRAVITY * dt.delta
			local tempY# = y + (dy * dt.delta)
			if dy <> 0
				if dy > 0
					if game.level.getCollisionTile(x - image.w2 + amount, tempY + image.h2 - amountY) > 0 or 
						game.level.getCollisionTile(x + image.w2 - amount, tempY + image.h2 -amountY) > 0 or
						game.level.getCollisionTile(x, tempY + image.h2 - amountY) > 0 then
						
						dy = 0
						jumping = false
						y = round( (tempY + image.h2) / Level.TILE_SIZE ) * Level.TILE_SIZE - image.h2
					else
						y = tempY
					endif
				else
					if game.level.getCollisionTile(x - image.w2 + amount, tempY - image.h2 ) > 0 or 
						game.level.getCollisionTile(x + image.w2 - amount, tempY - image.h2) > 0 or
						game.level.getCollisionTile(x, tempY - image.h2 ) > 0 then
						
						dy = 0
						y = round((tempY - image.h2) / Level.TILE_SIZE) * Level.TILE_SIZE + image.h2
						
					else
						y = tempY
					endif
				endif
			endif
		endif
		
		Local border% = 200
		If x-game.scrollX < border Then game.level.scrollHorizontal((x-game.scrollX)-border)
		If x-game.scrollX > WIDTH-border Then game.level.scrollHorizontal((x-game.scrollX)-(WIDTH-border))
	End Method
	
End Class

Function round%(f#)
	Return Floor(f+0.5)
End Function

Class Level
	Const TILE_SIZE% = 16
	Const GRAVITY# = 0.18
	
	Field map:Tile[][]
	Field width%, height%
	Field pixelWidth% = 0
	Field pixelHeight% = 0
	
	Field playerX%, playerY%
	
	' 32 across
	Global level1:=[
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,16,124,16,124,16,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
		115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

	Method load:Void()
		width = 32
		height = 16
		
		pixelWidth = width * TILE_SIZE
		pixelHeight = height * TILE_SIZE
		
		map = tileArray(width, height)
		
		For Local x:Int = 0 To width - 1
			For Local y:Int = 0 To height - 1
				map[x][y] = New Tile((level1 [ x + y * width ] ))
			Next
		Next
		
		playerX = 10
		playerY = 200
		
	End Method
	
	Method draw:Void()
		For Local x% = 0 To width - 1
			For Local y% = 0 To height - 1
				If map[x][y].frame > 0
					SetColor map[x][y].red, map[x][y].green, map[x][y].blue
					DrawRect Int(x * TILE_SIZE - game.scrollX), Int(y * TILE_SIZE - game.scrollY), TILE_SIZE, TILE_SIZE
				endif
			Next
		Next
	End Method
	
	Method scrollHorizontal:Void(change#)
		game.scrollX+=change

		If game.scrollX <0 Then
			game.scrollX = 0
		Else
			Local maxX% = pixelWidth - WIDTH
			If game.scrollX > maxX Then game.scrollX = maxX
		EndIf
	End Method
	
	Method getCollisionTile:Int(x:Float, y:Float)
		If x < 0 Or x >= pixelWidth Or y < 0 Or y >= pixelHeight Then Return 0
		
		local xx% = (Floor(x / TILE_SIZE)) 
		local yy% = (Floor(y / TILE_SIZE))
		
		Return map[xx][yy].frame
	End Method
End Class

Function tileArray:Tile[][](x_size:Int, y_size:Int)
	Local map:Tile[x_size][]
	For Local x:Int=0 Until x_size
	   map[x]=New Tile[y_size]
	Next
	Return map
End Function

Class Tile
	Field frame:Int
	Field red%, green%, blue%	
	
	Method New(frame:Int=0)
		self.frame = frame
		red = 255 - frame
		green = 255 - frame
		blue = 255 - frame
	End
End

Class DeltaTimer
	Field targetfps:Float = 60
	Field currentticks:Float
	Field lastticks:Float
	Field frametime:Float
	Field delta:Float
	
	Method New (fps:Float)
		targetfps = fps
		lastticks = Millisecs()
	End
	
	Method UpdateDelta:Void()
		currentticks = Millisecs()
		frametime = currentticks - lastticks
		delta = frametime / (1000.0 / targetfps)
		lastticks = currentticks
	End
End
